﻿# Monkey365 - the PowerShell Cloud Security Tool for Azure and Microsoft 365 (copyright 2022) by Juan Garrido
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

Function Get-HtmlHeader{
    <#
        .SYNOPSIS
        Set new HTML header
        .DESCRIPTION
        Set new HTML header
        .INPUTS

        .OUTPUTS

        .EXAMPLE

        .NOTES
	        Author		: Juan Garrido
            Twitter		: @tr1ana
            File Name	: Get-HtmlHeader
            Version     : 1.0

        .LINK
            https://github.com/silverhack/monkey365
    #>
    [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '', Scope='Function')]
    [CmdletBinding()]
    [OutputType([System.Xml.XmlDocument])]
    Param (
        [parameter(Mandatory= $false, HelpMessage= "Template")]
        [System.Xml.XmlDocument]$Template
    )
    Begin{
        $metaOptions = @(
            [PsCustomObject]@{
                tagName = "meta";
                properties = [PsCustomObject]@{
                    charset = "utf-8"
                };
            };
            [PsCustomObject]@{
                tagName = "title";
                text = "Monkey365 report";
            };
            [PsCustomObject]@{
                tagName = "meta";
                properties = [PsCustomObject]@{
                    name = "description";
                    content = "Monkey365 report"
                };
            };
            [PsCustomObject]@{
                tagName = "meta";
                properties = [PsCustomObject]@{
                    name = "viewport";
                    content = "width=device-width, initial-scale=1.0"
                };
            };
            [PsCustomObject]@{
                tagName = "meta";
                properties = [PsCustomObject]@{
                    name = "author";
                    content = "Juan Garrido"
                };
            };
        );
        $favicon = [PsCustomObject]@{
            tagName = "link";
                properties = [PsCustomObject]@{
                    rel = "icon";
                    type = "image/x-icon";
                    href = ""
                };
        }
        #main template
        If($PSBoundParameters.ContainsKey('Template') -and $PSBoundParameters['Template']){
            $TemplateObject = $PSBoundParameters['Template']
        }
        ElseIf($null -ne (Get-Variable -Name Template -Scope Script -ErrorAction Ignore)){
            $TemplateObject = $script:Template
        }
        Else{
            [xml]$TemplateObject = "<html></html>"
        }
        $_head = [PsCustomObject]@{
            init = [PsCustomObject]@{
                Meta = $metaOptions;
                Favicon = $favicon;
            }
            head = [PsCustomObject]@{};
        }
    }
    Process{
        Try{
            #Populate header obj
            If($null -ne (Get-Variable -Name Config -Scope Script -ErrorAction Ignore)){
                #Populate objects into internal Obj
                foreach($prop in $Script:Config.head.PsObject.Properties){
                    $_head.head | Add-Member -MemberType NoteProperty -Name $prop.Name -Value $prop.Value -Force
                }
            }
            #Construct xml
            #Create head
            $headObj = $TemplateObject.CreateNode(
                [System.Xml.XmlNodeType]::Element,
                $TemplateObject.Prefix,
                "head",
                $TemplateObject.NamespaceURI
            );
            #Add init elements to head
            ForEach($component in $_head.init.PsObject.Properties){
                Write-Verbose ($Script:messages.GenericAppendMessage -f $component.Name,"HTML head")
                ForEach($element in $component.Value){
                    #Get TagName
                    $tagName = $element | Select-Object -ExpandProperty tagName -ErrorAction Ignore
                    $properties = $element | Select-Object -ExpandProperty properties -ErrorAction Ignore
                    $text = $element | Select-Object -ExpandProperty text -ErrorAction Ignore
                    If($null -ne $tagName){
                        Try{
                            $tag = $TemplateObject.CreateNode(
                                [System.Xml.XmlNodeType]::Element,
                                $TemplateObject.Prefix,
                                $tagName.ToString(),
                                $TemplateObject.NamespaceURI
                            );
                            If($null -ne $properties){
                                ForEach($prop in $properties.Psobject.Properties){
                                    [void]$tag.SetAttribute($prop.Name,$prop.Value)
                                }
                            }
                            If($null -ne $text){
                                $tag.InnerText = $text.ToString()
                            }
                            Else{
                                $tag.InnerText = [string]::Empty
                            }
                            [void]$headObj.AppendChild($tag);
                        }
                        Catch{
                            Write-Error $_
                        }
                    }
                }
            }
            #Add elements to head
            ForEach($component in $_head.head.PsObject.Properties){
                If($component.Name.ToLower() -eq 'helpers'){
                    #Helpers will be added to the end of body HTML
                    continue
                }
                Write-Verbose ($Script:messages.GenericAppendMessage -f $component.Name,"HTML head")
                ForEach($element in $component.Value){
                    #Get TagName
                    $tagName = $element | Select-Object -ExpandProperty tagName -ErrorAction Ignore
                    $properties = $element | Select-Object -ExpandProperty properties -ErrorAction Ignore
                    $text = $element | Select-Object -ExpandProperty text -ErrorAction Ignore
                    If($null -ne $tagName){
                        Try{
                            $tag = $TemplateObject.CreateNode(
                                [System.Xml.XmlNodeType]::Element,
                                $TemplateObject.Prefix,
                                $tagName.ToString(),
                                $TemplateObject.NamespaceURI
                            );
                            If($null -ne $properties){
                                ForEach($prop in $properties.Psobject.Properties){
                                    If($prop.Name -eq 'crossorigin' -and $Script:mode -ne 'cdn'){
                                        continue
                                    }
                                    If($prop.Name -eq 'integrity' -and $Script:mode -ne 'cdn'){
                                        continue
                                    }
                                    If($Script:mode -eq 'cdn' -and $prop.Name -in @("src","href")){
                                        #Get baseUrl
                                        If($null -ne (Get-Variable -Name Repository -Scope Script -ErrorAction Ignore)){
                                            $_url = ("{0}/{1}" -f $Script:Repository,$prop.Value);
                                            $jsDelivr = Convert-UrlToJsDelivr -Url $_url -Latest
                                            [void]$tag.SetAttribute($prop.Name,$jsDelivr)
                                        }
                                        Else{
                                            Write-Warning $Script:messages.BaseUrlErrorMessage
                                        }
                                    }
                                    Else{
                                        If($prop.Name -in @("src","href")){
                                            $_url = ("{0}/{1}" -f $Script:LocalPath,$prop.Value);
                                            [void]$tag.SetAttribute($prop.Name,$_url)
                                        }
                                        Else{
                                            [void]$tag.SetAttribute($prop.Name,$prop.value)
                                        }
                                    }
                                }
                            }
                            If($null -ne $text){
                                $tag.InnerText = $text.ToString()
                            }
                            Else{
                                $tag.isEmpty = $True
                                $tag.InnerText = [string]::Empty
                            }
                            [void]$headObj.AppendChild($tag);
                        }
                        Catch{
                            Write-Error $_
                        }
                    }
                }
            }
            #return head object
            return $headObj
        }
        Catch{
            Write-Error $_
        }

    }
    End{
    }
}